package com.cyj.dream.security.component;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.cyj.dream.core.constant.SecurityConstants;
import com.cyj.dream.upms.model.dto.UserInfo;
import com.cyj.dream.upms.model.entity.SysDepartment;
import com.cyj.dream.upms.service.SosUser;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Description: 根据checktoken 的结果转化用户信息
 * @BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.security.component
 * @Author: ChenYongJia
 * @CreateTime: 2021-10-19 13:30
 * @Email: chen87647213@163.com
 * @Version: 1.0
 */
public class SosUserAuthenticationConverter implements UserAuthenticationConverter {

    private static final String N_A = "N/A";

    /**
     * Extract information about the user to be used in an access token (i.e. for resource
     * servers).
     *
     * @param authentication an authentication REPRESENTING a user
     * @return a map of key values representing the unique information about the user
     */
    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> response = new LinkedHashMap<>();
        response.put(USERNAME, authentication.getPrincipal());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return response;
    }

    /**
     * Inverse of {@link #convertUserAuthentication(Authentication)}. Extracts an
     * Authentication from a map.
     *
     * @param map a map of user information
     * @return an Authentication representing the user or null if there is none
     */
    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        if (map.containsKey(USERNAME)) {
            Collection<? extends GrantedAuthority> authorities = getAuthorities(map);

            String username = (String) map.get(SecurityConstants.DETAILS_USERNAME);
            Long id = Long.parseLong(map.get(SecurityConstants.DETAILS_USER_ID).toString());
            List<SysDepartment> deptList = (List<SysDepartment>) map.get(SecurityConstants.DETAILS_DEPT_INFO);
            deptList = JSON.parseObject(JSON.toJSONString(deptList), new TypeReference<ArrayList<SysDepartment>>() {
            });
            UserInfo userInfo = null;
            if (map.get(SecurityConstants.DETAILS_USERINFO) != null) {
                userInfo = BeanUtil.mapToBean((Map) map.get(SecurityConstants.DETAILS_USERINFO), UserInfo.class, false);
            } /*else if (map.get(USERNAME) != null) {
                userInfo = BeanUtil.mapToBean((Map) map.get(USERNAME), UserInfo.class, false);
            }*/

            SosUser user = new SosUser(id, deptList, username, N_A, true, true, true, true, authorities, userInfo);
            return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
        }
        return null;
    }

    private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
        Object authorities = map.get(AUTHORITIES);
        if (authorities instanceof String) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
        }
        if (authorities instanceof Collection) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList(
                    StringUtils.collectionToCommaDelimitedString((Collection<?>) authorities));
        }
        return AuthorityUtils.NO_AUTHORITIES;
    }

}
